from _decimal import Decimal
from django.utils import timezone
from rest_framework import serializers
from django_redis import get_redis_connection
from django.db import transaction


from goods.models import SKU
from .models import OrderInfo, OrderGoods


class CommitOrderSerializer(serializers.ModelSerializer):
    """保存订单序列化器"""

    class Meta:
        model = OrderInfo
        fields = ['order_id', 'pay_method', 'address']
        # order_id 只输出 paymethod/address 只输入
        read_only_fields = ['order_id']
        extra_kwargs = {
            'address': {
                'write_only': True,
                'required': True,
            },
            'pay_method': {
                'write_only': True,
                'required': True
            }
        }


    def create(self, validated_data):
        """重写序列化器的create方法 存储订单表/商品"""
        # 订单基本信息表 订单商品表 sku spu 四表要需同时成功或者一起失败 保证数据一致性


        # 获取当前保存订单时 需要的信息
        # 获取user对象
        user = self.context['request'].user  # ?不理解
        # 生成订单编号 当前时间 + user_id
        order_id = timezone.now().strftime('%Y%m%d%H%M%S') + "%09d" % user.id
        # 获取用户选择的收货地址
        address = validated_data.get('address')
        # 获取支付方式
        pay_method = validated_data.get('pay_method')

        # 订单状态： 如果用户选择的是货到付款则订单状态该为待发货， 如果用户选择支付宝支付， 订单该为待支付
        # status = '支付状态'
        status = (OrderInfo.ORDER_STATUS_ENUM['UNPAID']
                 if OrderInfo.PAY_METHODS_ENUM['ALIPAY'] == pay_method
                  else OrderInfo.ORDER_STATUS_ENUM['UNSEND'])

        # 开启事务
        with transaction.atomic():
            # 事物保存点
            save_point = transaction.savepoint()
            try:
                # 保存订单基本信息 OrderInfo
                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    total_count=0,
                    total_amount=Decimal('0.00'),
                    freight=Decimal('10.00'),
                    pay_method=pay_method,
                    status=status
                )

                # 从数据库中读取购物车被勾选的商品信息
                redis_conn = get_redis_connection('cart')
                cart_redis_dict = redis_conn.hgetall('cart_%d' % user.id)
                cart_selected_ids = redis_conn.smembers('selected_%d' % user.id)
                cart_selected_dict = {}
                for sku_id_bytes in cart_selected_ids:
                    cart_selected_dict[int(sku_id_bytes)] = int(cart_redis_dict[sku_id_bytes])

                # 遍历购物车被勾选的商品信息
                # skus = SKU.objects.filter(id__in=cart_selected_dict.keys())  # 这种方法一次取出， 在并发时有缓存问题
                for sku_id in cart_selected_dict:
                    # 增加循环查询
                    while True:

                        # 获取sku对象
                        sku = SKU.objects.get(id=sku_id)
                        # 获取当前sku_id商品要购买的数量
                        sku_count = cart_selected_dict[sku_id]

                        # 获取此刻sku库存和销量
                        origin_stock = sku.stock
                        origin_sales = sku.sales


                        # 判断库存
                        if sku_count > sku.stock:
                            raise serializers.ValidationError('库存不足')

                        import time
                        time.sleep(1)

                        # 计算新库存和销量
                        new_stock = origin_stock - sku_count
                        new_sales = origin_sales + sku_count

                        # 乐观锁
                        # 减少库存， 增加销量 SKU
                        result = SKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock, sales=new_sales)
                        # 此处数据操作有点迷糊


                        if result == 0:
                            continue  # 跳出本次循环进入下一次

                        # sku.stock -= sku_count
                        # sku.sales += sku_count
                        # sku.save()

                        # 修改SPU销量
                        spu = sku.goods
                        spu.sales += sku_count
                        spu.save()

                        # 保存订单商品信息
                        OrderGoods.objects.create(
                            order=order,
                            sku=sku,
                            count=sku_count,
                            price=sku.price
                        )


                         # 累加计算总数量和总价
                        order.total_count = order.total_count + sku_count
                        order.total_amount = order.total_amount + (sku.price * sku_count)
                        # 跳出循环， 继续下一个sku_id下单
                        break

                # 最后加入邮费和保存订单信息
                order.total_amount += order.freight
                order.save()
            except Exception:
                # 暴力回归， 一有异常数据还原
                transaction.savepoint_rollback(save_point)
                raise
            else:
                # 无异常则提交数据库保存
                transaction.savepoint_commit(save_point)

        # 消除购物车已结算的商品
        pl = redis_conn.pipeline()
        pl.hdel('cart_%d' % user.id, *cart_selected_ids)
        pl.srem('selected_%d' % user.id, *cart_selected_ids)
        pl.execute()

        return order


class CartSKUSerializer(serializers.ModelSerializer):
    """
    购物车商品数据序列化器
    """
    count = serializers.IntegerField(label='数量')

    class Meta:
        model = SKU
        fields = ('id', 'name', 'default_image_url', 'price', 'count')


class OrderSettlementSerializer(serializers.Serializer):
    # serializers.Serializers 正确
    """订单结算数据序列化器"""
    freight = serializers.DecimalField(label='运费', max_digits=10, decimal_places=2)
    skus = CartSKUSerializer(many=True)


class SKUSerializer(serializers.ModelSerializer):
    '''商品序列化器'''
    class Meta:
        model = SKU
        fields = ['id', 'name', 'price', 'default_image_url']

class ComentGoodsSerializer(serializers.ModelSerializer):
    '''评论列表序列化器'''
    sku = SKUSerializer()

    class Meta:
        model = OrderGoods
        fields = ['sku', 'price']


class CommitCommentSerializer(serializers.ModelSerializer):
    '''保存评论序列化器'''
    username = serializers.CharField(label='用户名', required=False)
    class Meta:
        model = OrderGoods
        fields = ['order', 'sku', 'comment', 'score', 'is_anonymous', 'username']
        extra_kwargs = {
            'sku':{'write_only':True},
            'order': {'write_only': True}
        }

    # 重写update方法
    def update(self, instance, validated_data):
        comment = validated_data.get('comment')
        score = validated_data.get('score')
        is_anonymous = validated_data.get('is_anonymous')

        instance.comment = comment
        instance.score = score
        instance.is_anonymous = is_anonymous
        instance.is_commented = True

        instance.save()

class OrderSkuSerializer(serializers.ModelSerializer):
    class Meta:
        model = SKU
        fields = ('default_image_url', 'name', 'price')


class OrderGoodsSerializer(serializers.ModelSerializer):
    sku = OrderSkuSerializer()

    class Meta:
        model = OrderGoods
        fields = ('sku', 'count')


class OrderListSerializer(serializers.ModelSerializer):
    """ 全部订单 """

    skus = OrderGoodsSerializer(many=True)
    create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S')
    class Meta:
        model = OrderInfo
        fields = ('create_time', 'order_id', 'pay_method', 'status','total_amount', 'freight', 'skus')

